package ar.edu.caece.pl.asem.codegenerator;

import ar.edu.caece.pl.asem.model.impl.treeelements.AbstractElement;
import ar.edu.caece.pl.asem.model.tree.Tree;
import ar.edu.caece.pl.asem.model.tree.TreeNode;
import ar.edu.caece.pl.asem.temp.TemporalGenerator;
import ar.edu.caece.pl.asin.manager.impl.ErrorManager;

public class CodeGenerator {

	//Singleton
	private static CodeGenerator instance = new CodeGenerator();
	private CodeGenerator(){}
	public static CodeGenerator getInstance() { return instance; }

	private Tree<AbstractElement> semanticTree;
	private Assembler assembler = new Assembler();

	public String generateCode() {
		StringBuffer code = new StringBuffer();
		
		// Clean old data run
		TemporalGenerator.getInstance().cleanInstance();
		
		// Header
		code.append(assembler.start());
		
		// Global Memory
		if(ErrorManager.debugEnabled) code.append("; CG-GlobalMemory - Init \n\n");
		code.append(assembler.generateGlobalMemory());
		if(ErrorManager.debugEnabled) code.append("; CG-GlobalMemory - Finish \n\n");

		// Program starts
		String program = start();
		
		// Temporal Code
		if(ErrorManager.debugEnabled) code.append("; CG-TempCode - Init \n\n");
		code.append( TemporalGenerator.getInstance().generateTemporalAssemblerCode() );
		if(ErrorManager.debugEnabled) code.append("; CG-TempCode - Finish \n\n");
		
		// PreDefined Functions
		if(ErrorManager.debugEnabled) code.append("; CG-PreDefined - Init \n\n");
		code.append(PreDefinedFunctions.sb.toString());
		if(ErrorManager.debugEnabled) code.append("; CG-PreDefined - Finish \n\n");
		
		// Programa
		if(ErrorManager.debugEnabled) code.append("; CG-Start - Init \n\n");
		code.append(program);
		if(ErrorManager.debugEnabled) code.append("; CG-Start - Finish \n\n");
		
		System.out.println(code);
		return code.toString();
	}
	
	/**
	 * Metodo que genera el código ASM del programa en si.
	 * @return
	 */
	private String start() {
		StringBuilder sb = new StringBuilder();
		
		TreeNode<AbstractElement> childCodigo = (TreeNode<AbstractElement>) semanticTree.getRoot().getChildren().get(1);

		semanticTree.fillData(childCodigo);
		childCodigo.getData().generateASMCode();
		sb.append(childCodigo.getData().code);
		
		return sb.toString();
	}

	public void setTree(Tree<AbstractElement> semanticTree) {
		this.semanticTree = semanticTree;
	}
}
